home *** CD-ROM | disk | FTP | other *** search
- /************************************************************
-
- RezParse.c
- C Source to Preditor 3
-
- Language Module Code for the "Rez" language
-
- © Copyright Evatac Software 1988-1996
- All rights reserved
-
- ************************************************************/
-
- #include "RezParse.h"
- #include <SetupA4.h>
- #include <MixedMode.h>
- #include <Ctype.h>
-
- #ifndef THINKC
- #include <A4Stuff.h>
- #else
- #define SetCurrentA4() 0; RememberA4()
- #define SetA4(x) SetUpA4()
- #endif
-
- #ifdef powerc
- ProcInfoType __procinfo = LanguageUPPInfo;
- #endif
-
- static languageGlobals globals;
- static ExternalCallbackBlock *callbacks;
-
-
- /*
- * * * * REZ LANGUAGE ELECTRIC HANDLER * * * * * *
- */
-
- static long _languageConvertToTabs(
- Char *text,
- long length,
- long hardTab
- )
- {
- int tabs = length / hardTab;
- int spaces = length % hardTab;
- int newLen = tabs + spaces;
-
- while (tabs-- > 0)
- *(text++) = 9;
- while (spaces-- > 0)
- *(text++) = ' ';
-
- return(newLen);
- }
-
- /*
- * _languageHandleElectric
- *
- * We get called only when there is no selection, and one of the
- * 3 electrics is pressed [;{}].
- */
- static void _languageHandleElectric(
- Char ch
- )
- {
- long anchor, end, pos, length;
- long i;
- long lineNumber, leading;
- short spacesPerTab, hardTab;
- Char text[256], *ptr = text;
-
- extGetSelection(callbacks, &anchor, &end);
-
- lineNumber = extLineFromPosition(callbacks, anchor);
- leading = extGetLeading(callbacks, lineNumber, &length,
- &spacesPerTab, &hardTab);
-
- pos = anchor;
- anchor = extLineToPosition(callbacks, lineNumber);
-
- /*
- * Get the indentation of the current line
- */
-
- if (ch == ';') {
-
- /*
- * Don't expand if we are in the middle a for statement. Doesn't
- * catch if for is not first word in line, or the (;;) expression
- * spans multiple lines
- */
-
- length = 256 - 4;
-
- extGetText(callbacks, anchor, end, text, &length);
- text[length] = 0;
- text[length+1] = 0;
-
- while (*ptr == ' ' || *ptr == '\t')
- ptr++;
- ptr[3] = 0;
-
- if (languageCStringCompare(ptr, (Char *) "for") == 0) {
-
- /*
- * Check to see if we are passed the ')'
- */
-
- ptr += 4;
-
- while (*ptr != 0) {
- if (*ptr == ')')
- break;
- ptr++;
- }
-
- if (*ptr == 0) {
- extInsert(callbacks, (Char *) ";", 1);
- return;
- }
- }
-
- /*
- * Now create the text to insert
- */
-
- text[0] = ';';
- text[1] = '\r';
-
- i = _languageConvertToTabs(text + 2, leading, hardTab);
-
- extInsert(callbacks, text, i + 2);
- }
-
- else if (ch == '}') {
-
- Int32 x;
- Boolean sameLine;
-
- /*
- * See if we are on a blank line. If we are, put the '}' on it,
- * otherwise, insert on a new line
- */
-
- x = extLineEnd(callbacks, lineNumber);
- sameLine = (x - anchor == length);
-
- text[0] = '}';
- text[1] = 0;
-
- if ((x = extFindMatch(callbacks, text, end)) == -1) {
- extInsert(callbacks, (Char *) "}", 1);
- return;
- }
-
- lineNumber = extLineFromPosition(callbacks, x);
- leading = extGetLeading(callbacks, lineNumber, &length,
- &spacesPerTab, &hardTab);
-
- /*
- * Now create the text to insert
- */
-
- if (sameLine) {
- extSetSelection(callbacks, anchor, pos);
- x = 0;
- }
- else {
- text[0] = '\r';
- x = 1;
- }
-
- i = _languageConvertToTabs(text + x, leading, hardTab);
-
- text[i+x] = '}';
-
- extInsert(callbacks, text, i + x + 1);
- }
-
- else if (ch == '{') {
-
- /*
- * Create the text to insert
- */
-
- text[0] = '{';
- text[1] = '\r';
-
- i = _languageConvertToTabs(text + 2, leading + spacesPerTab, hardTab);
-
- extInsert(callbacks, text, i + 2);
- }
- }
-
- /*
- * * * * REZ LANGUAGE INDENTING HANDLER * * * * * *
- */
-
- /*
- * _languageHandleIndent
- *
- * Indent the selected lines according to the buffer indentation settings
- */
- static void _languageHandleIndent(
- void *extData
- )
- {
- long anchor, end, pos, length;
- long lineStart;
- long i, x, newPos = -1;
- long lineNumber, endLineNumber, leading;
- short spacesPerTab, hardTab;
- Char text[256], ch;
-
- extGetSelection(callbacks, &anchor, &end);
-
- if (anchor > end) {
- pos = anchor; anchor = end; end = pos; /* Swap */
- }
-
- lineNumber = extLineFromPosition(callbacks, anchor);
- endLineNumber = extLineFromPosition(callbacks, end);
-
- /*
- * Indent each line in the selection
- */
-
- while (lineNumber <= endLineNumber) {
-
- if (lineNumber <= 1) {
- lineNumber++;
- continue;
- }
-
- leading = extGetLeading(callbacks, lineNumber, &length,
- &spacesPerTab, &hardTab);
-
- lineStart = extLineToPosition(callbacks, lineNumber);
-
- /*
- * Select the leading spaces/tabs
- */
-
- extSetSelection(callbacks, lineStart, lineStart + length);
-
- /*
- * Scan back previous lines for a line that we can relate to
- */
-
- x = 1;
-
- for (;;) {
-
- if (lineNumber - x < 1)
- break;
-
- leading = extGetLeading(callbacks, lineNumber - x, &length,
- &spacesPerTab, &hardTab);
-
- end = extLineEnd(callbacks, lineNumber - x);
- pos = extLineToPosition(callbacks, lineNumber - x);
-
- /* Skip Blank lines */
-
- if (length == (end - pos)) {
- x++;
- continue;
- }
-
- i = pos + length;
-
- /*
- * Indent right if line contains a left bracket
- */
-
- extScanContents(callbacks, i);
-
- while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
-
- if (ch == '{') {
- leading += spacesPerTab;
- break;
- }
- }
-
- extDoneScan(callbacks);
-
-
- /*
- * Indent the line
- */
-
- i = _languageConvertToTabs(text, leading, hardTab);
-
- extInsert(callbacks, text, i);
-
- if (newPos == -1)
- newPos = lineStart + i;
- break;
- }
-
- lineNumber++;
- }
-
- if (newPos >= 0)
- extSetSelection(callbacks, newPos, newPos);
- }
-
- /*
- * * * * REZ LANGUAGE PARSER * * * * * *
- */
-
- /*
- * _languageBuildString
- *
- * Build up a literal string or literal contant "foo" or 'foo'
- */
- static void _languageBuildString(
- languageToken *token,
- int c
- )
- {
- Int32 index = 1, size = kTokenStringSize;
- int origC = c;
-
- token->string[1] = c;
- token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (index < size)
- token->string[++index] = c;
-
- if (c == origC)
- break;
-
- else if (c == '\\') {
-
- c = languageGetChar(&globals, callbacks);
-
- if (c != -1) {
-
- if (index < size)
- token->string[++index] = c;
- }
- }
- }
-
- token->string[0] = index; /* So string can be used as C or Pascal string */
- token->string[++index] = 0;
- }
-
- /*
- * _languageBuildWhiteSpace
- *
- * Build up a directive (i.e. #define, etc)
- */
- static void _languageBuildWhiteSpace(
- languageToken *token,
- int c
- )
- {
- token->type = kSymbolWhiteSpace;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
- c != '\r' && c != '\f' && c != '\b') {
- // if (!isspace(c)) {
- languageUngetChar(&globals, c);
- return;
- }
- }
- }
-
- /*
- * _languageBuildComment
- *
- */
- static void _languageBuildComment(
- languageToken *token,
- int c
- )
- {
- Boolean wasStar;
-
- token->type = kSymbolComment;
- globals.startLastComment = globals.position;
-
- c = languageGetChar(&globals, callbacks);
-
- if (c =='*') {
-
- wasStar = false;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c == '*')
- wasStar = true;
- else if (c != '/' || !wasStar)
- wasStar = false;
- else
- break;
- }
- }
- }
-
- /*
- * _languageBuildNumber
- *
- */
- static void _languageBuildNumber(
- languageToken *token,
- int c
- )
- {
- Int32 index = 0, size = kTokenStringSize;
-
- token->type = kSymbolIntConstant;
-
- if (c == '$') {
-
- c = languageGetChar(&globals, callbacks);
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
- ;
- else
- break;
- }
- }
-
- else { /* decimal */
-
- if (index < size)
- token->string[++index] = c;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= '0' && c <= '9') {
- if (index < size)
- token->string[++index] = c;
- }
- else
- break;
- }
-
- if (c == '.') {
-
- token->type = kSymbolFloatConstant;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= '0' && c <= '9')
- ;
- else
- break;
- }
- }
-
- if (c == 'e' || c == 'E') {
-
- token->type = kSymbolFloatConstant;
-
- c = languageGetChar(&globals, callbacks);
-
- if (c == '-' || c == '+')
- c = languageGetChar(&globals, callbacks);
-
- while (c != -1) {
-
- if (c >= '0' && c <= '9')
- ;
- else
- break;
-
- c = languageGetChar(&globals, callbacks);
- }
- }
-
- token->string[0] = index; /* So string can be used as C or Pascal string */
- token->string[++index] = 0;
- }
-
- if (c != -1)
- languageUngetChar(&globals, c);
- }
-
- /*
- * _languageBuildInclude
- */
- static void _languageBuildInclude(
- languageToken *token,
- int c
- )
- {
- Int32 index = 0, size = kTokenStringSize;
-
- languageUngetChar(&globals, c);
- _languageBuildWhiteSpace(token, c);
-
- token->type = kSymbolInclude;
-
- if ((c = languageGetChar(&globals, callbacks)) == '\"' || c == '<') {
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
- || c >= '0' && c <= '9' || c == '.') {
-
- if (index < size)
- token->string[++index] = c;
- }
- else {
- break;
- }
- }
- }
-
- token->string[0] = index; /* So string can be used as C or Pascal string */
- token->string[++index] = 0;
- }
-
- /*
- * _languageBuildWord
- *
- *
- */
- static void _languageBuildWord(
- languageToken *token,
- int c
- )
- {
- Int32 index = 1, size = kTokenStringSize;
-
- token->type = kSymbolIdentifier;
-
- token->string[1] = c;
-
- while ((c = languageGetChar(&globals, callbacks)) != -1) {
-
- if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
- || c >= '0' && c <= '9') {
-
- if (index < size)
- token->string[++index] = c;
- }
- else {
-
- languageUngetChar(&globals, c);
- break;
- }
- }
-
- token->string[0] = index; /* So string can be used as C or Pascal string */
- token->string[++index] = 0;
-
- /*
- * Since hashing into a large reserved word table takes time, the reserved
- * word table is not loaded for "function" scanning. We do our own
- * limited keyword check
- */
-
- if (!languageHasTable(&globals)) {
-
- Char *scan = token->string + 1;
-
- if (languageCStringCompare(scan, (Char *) "type") == 0)
- token->type = kSymbolReservedWord;
- else if (languageCStringCompare(scan, (Char *) "resource") == 0)
- token->type = kSymbolReservedWord;
-
- return;
- }
-
- else if (languageTableLookup((&globals), token->string + 1))
- token->type = kSymbolReservedWord;
- else if (languageCustomTableLookup((&globals), token->string + 1))
- token->type = kSymbolCustomWord;
- }
-
- /*
- * _languageConcatPStrings
- *
- * Concatenate two Pascal strings by attaching the second string on
- * the end of the first string.
- */
- static void _languageConcatPStrings(
- Char *first,
- Char *second
- )
- {
- BlockMove(second + 1, first + first[0] + 1, (long) second[0]);
- first[0] += second[0];
- }
-
- /*
- * _languageGetNextToken
- */
- static languageToken *_languageGetNextToken(void)
- {
- int first, second;
- Int16 previousType;
- languageToken *token = &globals.token;
-
- previousType = token->type;
- token->startLocation = globals.position;
- token->majorType = -1;
-
- if ((first = languageGetChar(&globals, callbacks)) == -1)
- return(nil);
-
- token->type = first;
-
- second = languagePeekChar(&globals, callbacks);
-
- if (previousType == kSymbolReservedWord &&
- token->string[1] == '#' && token->string[3] == 'n') {
-
- _languageBuildInclude(token, first);
- first = 0;
- }
-
- switch(first) {
-
- /* "strings" */
- /* 'character constants' */
-
- case '\"':
- case '\'':
- _languageBuildString(token, first);
- break;
-
- case ';':
- globals.startLastComment = -1;
- break;
-
- /* preprocessor directive */
-
- case '#':
- _languageBuildWord(token, first);
- globals.startLastComment = -1;
- break;
-
- /* white space */
-
- case ' ': case '\t': case '\v': case '\n': case '\r': case '\f': case '\b':
- _languageBuildWhiteSpace(token, first);
- break;
-
- case '/':
- if (second == '*')
- _languageBuildComment(token, first);
- break;
-
- /* ., .*, .NUM */
-
- case '.':
- if (second >= '0' && second <= '9')
- _languageBuildNumber(token, first);
- break;
-
- /* the rest */
-
- default:
- if (first >= '0' && first <= '9')
- _languageBuildNumber(token, first);
- else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
- first == '_')
- _languageBuildWord(token, first);
-
- /* Something weird, let the parser decide. */
-
- break;
- }
-
- token->endLocation = globals.position;
-
- return(token);
- }
-
- void languageMain(
- ExternalCallbackBlock *extCallbacks,
- WindowRef window,
- long options,
- void *extData
- );
-
- /*
- * languageMain
- *
- * This is the main entrypoint to the CODE module of a language module.
- * The following operations are defined:
- *
- * kLanguageParse Parse the source file, returning positions of all tokens
- * in the file.
- * kLanguageFunctions Parse the source file, returning the position of just the
- * functions in the source file
- * kLanguageIncludes Parse the source file, returning the #include files
- * kLanguageTemplate Expand macro -- insert template
- * kLanguageIndentLine
- * kLanguageElectric Handle electric characters (i.e. }, {, ; )
- */
- void main(
- ExternalCallbackBlock *extCallbacks,
- WindowRef window,
- long options,
- void *extData
- )
- {
- languageToken *token, saveToken;
- Int16 i, type;
- Boolean isType;
- long saved_a4;
-
- saved_a4 = SetCurrentA4();
-
- languageInit(&globals, extCallbacks, options);
-
- callbacks = extCallbacks;
-
- if (options == kLanguageTemplate) {
-
- languageDefaultHandler(&globals, callbacks, options, extData);
- }
-
- else if (options == kLanguageElectric) {
-
- _languageHandleElectric((Char) extData);
- }
-
- else if (options == kLanguageIndent) {
-
- _languageHandleIndent(extData);
- }
-
- else if (options <= kLanguageIncludes) {
-
- /*
- * Now parse the file, returning a series of valid return token types:
- *
- * kFunction
- * kKeyword
- * kComment
- * kCustomKeyword
- */
-
- while ((token = _languageGetNextToken()) != nil) {
-
- type = token->type;
-
- if (type == kSymbolReservedWord) {
-
- token->majorType = kKeyword;
-
- /*
- * Check for keyword 'type' or 'resource'
- */
-
- if (options == kLanguageFunctions &&
- (token->string[1] == 't' ||
- token->string[1] == 'r' && token->string[3] == 's')) {
-
- isType = (token->string[1] == 't');
-
- _languageBuildWhiteSpace(token,
- languageGetChar(&globals, callbacks));
-
- if (languageGetChar(&globals, callbacks) == '\'') {
-
- /* Pull out the 'TYPE' info */
-
- for (i=1; i<=4; i++)
- token->string[i] =
- languageGetChar(&globals, callbacks);
-
- token->string[0] = 4;
- token->string[5] = 0;
-
- /* Skip the matching "'" */
-
- languageGetChar(&globals, callbacks);
-
- saveToken = *token;
- saveToken.startLocation = globals.position - 5;
- saveToken.endLocation = globals.position - 1;
-
- /*
- * Get the resource id for 'resource' definitions
- */
-
- if (!isType) {
-
- while ((token = _languageGetNextToken()) != nil &&
- token->type != kSymbolIntConstant)
- ;
-
- saveToken.endLocation = globals.position;
-
- /*
- * Append the resource id to the end of the definition string
- */
-
- if (token != nil) {
-
- saveToken.string[++(*saveToken.string)] = ' ';
-
- _languageConcatPStrings(saveToken.string, token->string);
-
- saveToken.string[(*saveToken.string) + 1] = 0;
- }
- }
-
- saveToken.majorType = kDefinition;
- saveToken.commentLocation = globals.startLastComment;
- extTokenReturn(callbacks, &saveToken);
- }
- }
- }
-
- else if (type == kSymbolCustomWord) {
- token->majorType = kCustomKeyword;
- }
-
- else if (type == kSymbolComment)
- token->majorType = kComment;
-
- else if (type == kSymbolInclude && options == kLanguageIncludes) {
-
- token->majorType = kDefinition;
-
- extTokenReturn(callbacks, token);
- }
-
- /*
- * Only return a token if it's a interesting token, and
- * if we are doing a full parse
- */
-
- if (token->majorType >= 0 && options == kLanguageParse)
- extTokenReturn(callbacks, token);
- }
- }
-
- /*
- * Clean up after ourselves
- */
-
- languageDone(&globals, callbacks);
-
- SetA4(saved_a4);
- }
-